package cn.wolfcode.business.service.impl;

import java.io.InputStream;
import java.util.*;
import java.util.stream.Collectors;

import cn.wolfcode.business.domain.BusBpmnInfo;
import cn.wolfcode.business.domain.BusServiceItem;
import cn.wolfcode.business.service.IBusBpmnInfoService;
import cn.wolfcode.business.service.IBusServiceItemService;
import cn.wolfcode.business.vo.CarPackageAuditVO;
import cn.wolfcode.business.vo.HistoryListVO;
import cn.wolfcode.common.utils.DateUtils;
import cn.wolfcode.common.utils.PageUtils;
import cn.wolfcode.common.utils.SecurityUtils;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.engine.HistoryService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Comment;
import org.activiti.engine.task.Task;
import org.activiti.image.impl.DefaultProcessDiagramGenerator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import cn.wolfcode.business.mapper.BusCarPackageAuditMapper;
import cn.wolfcode.business.domain.BusCarPackageAudit;
import cn.wolfcode.business.service.IBusCarPackageAuditService;
import org.springframework.transaction.annotation.Transactional;

/**
 * 套餐审核Service业务层处理
 * 
 * @author wolfcode
 * @date 2025-04-10
 */
@Service
public class BusCarPackageAuditServiceImpl implements IBusCarPackageAuditService 
{
    @Autowired
    private BusCarPackageAuditMapper busCarPackageAuditMapper;
    @Autowired
    private RepositoryService repositoryService;
    @Autowired
    private RuntimeService runtimeService;
    @Autowired
    private IBusServiceItemService serviceItemService;
    @Autowired
    private HistoryService historyService;
    @Autowired
    private TaskService taskService;
    @Autowired
    private IBusBpmnInfoService bpmnInfoService;

    /**
     * 查询套餐审核
     * 
     * @param id 套餐审核主键
     * @return 套餐审核
     */
    @Override
    public BusCarPackageAudit selectBusCarPackageAuditById(Long id)
    {
        return busCarPackageAuditMapper.selectBusCarPackageAuditById(id);
    }

    /**
     * 查询套餐审核列表
     * 
     * @param busCarPackageAudit 套餐审核
     * @return 套餐审核
     */
    @Override
    public List<BusCarPackageAudit> selectBusCarPackageAuditList(BusCarPackageAudit busCarPackageAudit)
    {
        return busCarPackageAuditMapper.selectBusCarPackageAuditList(busCarPackageAudit);
    }

    /**
     * 新增套餐审核
     * 
     * @param busCarPackageAudit 套餐审核
     * @return 结果
     */
    @Override
    public int insertBusCarPackageAudit(BusCarPackageAudit busCarPackageAudit)
    {
        busCarPackageAudit.setCreateTime(DateUtils.getNowDate());
        return busCarPackageAuditMapper.insertBusCarPackageAudit(busCarPackageAudit);
    }

    /**
     * 修改套餐审核
     * 
     * @param busCarPackageAudit 套餐审核
     * @return 结果
     */
    @Override
    public int updateBusCarPackageAudit(BusCarPackageAudit busCarPackageAudit)
    {
        return busCarPackageAuditMapper.updateBusCarPackageAudit(busCarPackageAudit);
    }

    /**
     * 批量删除套餐审核
     * 
     * @param ids 需要删除的套餐审核主键
     * @return 结果
     */
    @Override
    public int deleteBusCarPackageAuditByIds(Long[] ids)
    {
        return busCarPackageAuditMapper.deleteBusCarPackageAuditByIds(ids);
    }

    /**
     * 删除套餐审核信息
     * 
     * @param id 套餐审核主键
     * @return 结果
     */
    @Override
    public int deleteBusCarPackageAuditById(Long id)
    {
        return busCarPackageAuditMapper.deleteBusCarPackageAuditById(id);
    }

    @Override
    public void updateInstanceIdById(Long auditId, String processInstanceId) {
        busCarPackageAuditMapper.updateInstanceIdById(auditId,processInstanceId);
    }

    /*进度查看*/
    @Override
    public InputStream getProcessImg(Long instanceId) {
        if(instanceId == null){
            throw new RuntimeException("非法参数");
        }
        //在这里定义一个流程定义id 因为后面不管能不能查到流程实例都要获取流程定义id
        String processDefinitionId = null;
        //获取当前活动节点
        List<String> activeActivityIds = new ArrayList<>();
        //获取流程实例对象
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(instanceId.toString()).singleResult();
        //若查询不到流程实例（即流程被撤销）
        if(processInstance == null){
            //那么就要查询历史流程实例
            HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(instanceId.toString()).singleResult();
            //通过历史流程实例查询流程定义id
            processDefinitionId = historicProcessInstance.getProcessDefinitionId();

        //若查到了流程实例（即流程在审批中）
        }else{
            //查询当前的流程定义id
            processDefinitionId = processInstance.getProcessDefinitionId();
            //获取当前活动节点（只有在审批中才有活动节点）
            activeActivityIds = runtimeService.getActiveActivityIds(instanceId.toString());
        }
        //获取绘图插件
        DefaultProcessDiagramGenerator defaultProcessDiagramGenerator = new DefaultProcessDiagramGenerator();
        //通过流程实例id获取bpmnModel对象
        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
        //生成流程图并以流的形式返回
        InputStream inputStream = defaultProcessDiagramGenerator.generateDiagram(
                bpmnModel,
                activeActivityIds, //只有在审批过程中才会有高亮节点，若撤销审批，则activeActivityIds为空
                Collections.emptyList(),
                "宋体",
                "宋体",
                "宋体"
        );
        return inputStream;
    }

    /*流程撤销*/
    @Override
    @Transactional
    public int processCancel(Long id) {
        if(id == null){
            throw new RuntimeException("非法参数");
        }
        //从快照表中查询是否存在当前发起的审核流程
        BusCarPackageAudit busCarPackageAudit = this.selectBusCarPackageAuditById(id);
        if(busCarPackageAudit == null){
            throw new RuntimeException("非法参数");
        }
        //审核中才可以撤销
        if(!BusCarPackageAudit.STATUS_IN_PROGRESS.equals(busCarPackageAudit.getStatus())){
            throw new RuntimeException("必须处于审核中的流程才可以撤销");
        }
        //将快照表审核状态改为审核撤销
        busCarPackageAuditMapper.updateAuditStatusById(BusCarPackageAudit.STATUS_CANCEL,id);
        //删除流程实例
        runtimeService.deleteProcessInstance(busCarPackageAudit.getInstanceId(),"流程撤销");

        //将服务项状态修改为初始化 业务表中可以获取到服务项id
        return serviceItemService.changeStatusById(busCarPackageAudit.getServiceItemId(), BusServiceItem.AUDITSTATUS_INIT);
    }

    /*查询历史任务集合*/
    @Override
    public List<HistoryListVO> getHistoryTasks(Long instanceId) {
        //参数合理化验证
        if(instanceId == null){
            throw new RuntimeException("非法参数");
        }
        //查询当前流程实例对应的所有历史任务
        List<HistoricTaskInstance> historicTaskList = historyService.createHistoricTaskInstanceQuery().processInstanceId(instanceId.toString()).list();

       /* List<HistoryListVO> historyList = new ArrayList<>();
        //遍历所有查询到的历史任务
        for (HistoricTaskInstance task : historicTaskList) {
            HistoryListVO vo = new HistoryListVO();
            vo.setTaskName(task.getName());
            vo.setStartTime(task.getStartTime().toString());
            vo.setEndTime(task.getEndTime().toString());
            vo.setDurationInMillis(task.getDurationInMillis()/1000/60 + "分");
            //查询批注信息
            List<Comment> taskComments = taskService.getTaskComments(task.getId());
            if(taskComments != null && taskComments.size() > 0){
                for (Comment taskComment : taskComments) {
                    vo.setComment(taskComment.getFullMessage());
                }
            }
            //将封装好的数据存入list中
            historyList.add(vo);
        }*/

        //优化方法一
        List<HistoryListVO> historyList = historicTaskList.stream().map(task -> {
            HistoryListVO vo = new HistoryListVO();
            vo.setTaskName(task.getName());
            vo.setStartTime(task.getStartTime());
            if(task.getEndTime() != null){
                vo.setEndTime(task.getEndTime());
                vo.setDurationInMillis(task.getDurationInMillis()/1000/60 + "分");
            }
            List<Comment> taskComments = taskService.getTaskComments(task.getId());
            if(taskComments != null && taskComments.size() > 0){
                for (Comment taskComment : taskComments) {
                    vo.setComment(taskComment.getFullMessage());
                }
            }
            return vo;
        }).collect(Collectors.toList());
        return historyList;
    }

    @Override
    //查询待办任务
    public List<BusCarPackageAudit> todoTasks(BusCarPackageAudit busCarPackageAudit) {
        //获取当前用户id
        Long userId = SecurityUtils.getUserId();
        //获取流程定义的Key  在BpmnInfo对象中获取
        BusBpmnInfo busBpmnInfo = bpmnInfoService.selectBusBpmnInfoByTypeId(BusCarPackageAudit.FLOW_AUDIT_TYPE);
        String processDefinitionKey = busBpmnInfo.getProcessDefinitionKey();
        //根据BusinessKey和UserId查询对应的待办任务
        List<Task> taskList = taskService.createTaskQuery().processDefinitionKey(processDefinitionKey).taskAssignee(userId.toString()).list();

        if(taskList == null || taskList.size() <= 0){
            //说明没查到任务
            return Collections.emptyList();
        }
        /*//创建一个流程实例集合
        List<String> processInstanceIds = new ArrayList<>();
        for (Task task : taskList) {
            processInstanceIds.add(task.getProcessInstanceId()) ;
        }*/

        /*//stream简化版1
        List<String> processInstanceIds = taskList.stream().map(task -> {
            return task.getProcessInstanceId();
        }).collect(Collectors.toList());*/

       /* //stream简化版2
        List<String> processInstanceIds = taskList.stream().map(task -> task.getProcessInstanceId()).collect(Collectors.toList());*/
        //stream简化版3 获取所有的流程实例id 方法的引用
        List<String> processInstanceIds = taskList.stream().map(Task::getProcessInstanceId).collect(Collectors.toList());
        //进行分页处理
        PageUtils.startPage();
        //通过流程实例id集合，可以查询出对应的套餐审批记录表中的信息
        if(processInstanceIds.size() > 0){
            //封装额外请求参数processInstanceIds   map类型
            busCarPackageAudit.getParams().put("processInstanceIds",processInstanceIds);
        }
        return busCarPackageAuditMapper.selectBusCarPackageAuditList(busCarPackageAudit);

    }

    /**
     * 审批功能
     * @param vo
     * @return
     */
    @Override
    @Transactional
    public void audit(CarPackageAuditVO vo) {
        //对象不能为空
        if(vo == null){
            throw new RuntimeException("非法参数");
        }
        //前端传过来的审批单id和审批状态也不能为空
        if(vo.getId() == null || vo.getAuditStatus() == null){
            throw new RuntimeException("非法参数");
        }
        //根据套餐审批记录id查询审批记录对象
        BusCarPackageAudit carPackageAudit = this.selectBusCarPackageAuditById(vo.getId());
        if(carPackageAudit == null){
            throw new RuntimeException("非法参数");
        }
        //获取状态  只有审批中才能进行审批
        if(!(BusCarPackageAudit.STATUS_IN_PROGRESS.equals(carPackageAudit.getStatus()))){
            throw new RuntimeException("只有在审批状态中才能进行审批");
        }
        //从审批记录对象中获取到流程实例instanceId和当前登录用户
        String instanceId = carPackageAudit.getInstanceId();
        Long userId = SecurityUtils.getUserId();
        //获取到对应的当前任务信息  这一步不管金额是否大于3000都是店长先审核，所以传入参数userId
        Task task = taskService.createTaskQuery().processInstanceId(instanceId).taskAssignee(userId.toString()).singleResult();
        if(task == null){
            throw new RuntimeException("非法参数");
        }
        //拼接批注信息
        StringBuilder msg = new StringBuilder("审批意见：[");
        msg.append(SecurityUtils.getUsername());
        msg.append(":");
        Boolean auditStatus = BusCarPackageAudit.STATUS_PASS.equals(vo.getAuditStatus());
        if(auditStatus){
            // 通过
            msg.append("审批通过，批注信息:");
        } else{
            // 不通过
            msg.append("审批拒绝，批注信息:");
        }
        msg.append(vo.getInfo()).append("]");
        //插入批注信息
        taskService.addComment(task.getId(),instanceId,msg.toString());

        //为连线上面的 ${shopOwner}赋值。该变量为店长的同意或拒绝。（就是我们的审批意见）
        Map<String,Object> params = new HashMap<>();
        params.put("shopOwner",auditStatus);
        //如果同意，还要为连线上的另一个流程变量赋值。 disCountPrice 折扣价用于判定我们是否需要财务审批还是直接结束流程。
        // 强调！！！！！！！！！！！Activiti7不支持 BigDecimal 类型。！！！！！！！！！！！！！所以转化成longValue
        if(auditStatus){
            //如果是同意 那么需要给disCountPrice赋值
            params.put("disCountPrice",carPackageAudit.getServiceItemPrice().longValue());
        }
        //完成任务并赋值，控制流程走向
        taskService.complete(task.getId(),params);
        //业务线
        if(auditStatus){
            //若是审批通过
            //根据流程实例 id 继续查询任务。（当前任务完成后的下一个任务）。这里条件不能添加负责人！！！
            Task nextTask = taskService.createTaskQuery()
                    .processInstanceId(instanceId)
                    .singleResult();
            if(nextTask == null){
                //如果没有下一个任务
                //直接将审核状态列表状态修改为 --> 审批通过
                busCarPackageAuditMapper.updateAuditStatusById(BusCarPackageAudit.STATUS_PASS,carPackageAudit.getId());
                //在将其对应的服务项状态也一并修改为 --> 审批通过
                serviceItemService.changeStatusById(carPackageAudit.getServiceItemId(),BusServiceItem.AUDITSTATUS_APPROVED);
            }
            //如果有下一个任务，说明流程没有结束。不用管让其继续执行。
        } else {
            //若是审批拒绝
            //直接将审核状态列表状态修改为 --> 审批拒绝
            busCarPackageAuditMapper.updateAuditStatusById(BusCarPackageAudit.STATUS_REJECT,carPackageAudit.getId());
            //在将其对应的服务项状态也一并修改为 --> 审批拒绝。
            serviceItemService.changeStatusById(carPackageAudit.getServiceItemId(),BusServiceItem.AUDITSTATUS_REPLY);
        }
    }
}
